using System;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Imaging;
using System.Collections;
using System.Reflection;
using System.ComponentModel;
using System.Data;
using System.Runtime.InteropServices;
using System.Text;
using System.Resources;

namespace SmartControls
{
    public class TwoLineListBox : OwnerDrawnList
    {
        #region Private variables
        // Variables used for drawing
        private string m_line1Property = null;
        private string m_line2Property = null;
        private string m_itemImageProperty = null;

        private int m_textHeightLine1;			// The height of a line of text, calculated from the font
        private int m_textHeightLine2;			// The height of a line of text, calculated from the font

		private Font m_fontLine1;					// The font used for drawing the text on line 1
        private Font m_fontLine2;					// The font used for drawing the text on line 2

		private ImageList m_imageList = new ImageList();
        #endregion

        #region Constants
        // The distance between the left edge of the control, or the icon if used, and the
        // start of the line 1 and line 2 text.
        private const int TEXT_PADDING_X = 4;
        // The distance between the left edge of the control and the item image
        private const int IMAGE_PADDING_X = 4;
        private const int IMAGE_PADDING_Y = 4;
        #endregion

        #region Properties
        // Hide the base class font. We use FontLine1 and FontLine2. Also hide it from the designer.

        private new Font Font
        {
            get { return null; }
        }

        public Font FontLine1
        {
            [System.Diagnostics.DebuggerStepThrough]
            get 
			{
				if (m_fontLine1 == null)
					m_fontLine1 = new Font("Tahoma", 8.0F, FontStyle.Regular);

				return m_fontLine1; 
			}
            [System.Diagnostics.DebuggerStepThrough]
            set
            {
                if (value != m_fontLine1)
                {
                    m_fontLine1 = value;
                    OnFontChanged(EventArgs.Empty);
                }
            }
        }

		public Font FontLine2
		{
			[System.Diagnostics.DebuggerStepThrough]
			get
			{
				if (m_fontLine2 == null)
					m_fontLine2 = new Font("Tahoma", 6.0F, FontStyle.Regular);

				return m_fontLine2;
			}
			[System.Diagnostics.DebuggerStepThrough]
			set
			{
				if (value != m_fontLine2)
				{
					m_fontLine2 = value;
					OnFontChanged(EventArgs.Empty);
				}
			}
		}

		protected override int ItemHeight
		{
			get
			{
				return base.ItemHeight;
			}
		}

        public string Line1DisplayMember
        {
            [System.Diagnostics.DebuggerStepThrough]
            get { return this.m_line1Property; }
            [System.Diagnostics.DebuggerStepThrough]
            set
            {
                this.m_line1Property = value;
                Invalidate();
            }
        }

        public string Line2DisplayMember
        {
            [System.Diagnostics.DebuggerStepThrough]
            get { return this.m_line2Property; }
            [System.Diagnostics.DebuggerStepThrough]
            set
            {
                this.m_line2Property = value;
                Invalidate();
            }
        }

		public string ItemImageDisplayMember
        {
            [System.Diagnostics.DebuggerStepThrough]
            get { return this.m_itemImageProperty; }
            [System.Diagnostics.DebuggerStepThrough]
            set
            {
                this.m_itemImageProperty = value;
                Invalidate();
            }
        }

		public ImageList ImageList
		{
			get
			{
				return this.m_imageList;
			}
			set
			{
				this.m_imageList = value;
				Invalidate();
			}
		}

        #endregion

        #region Property Change Methods
        #endregion

        #region Events
        #endregion

        #region Methods
        public TwoLineListBox() : base()
        {
            Line1DisplayMember = "";
            Line2DisplayMember = "";
            ItemImageDisplayMember = "";
			ImageList = new ImageList();
            this.Size = new Size(224, 200);
        }

		protected override void RecalcItemHeight()
		{
			Graphics g = this.CreateGraphics();
			m_textHeightLine1 = g.MeasureString("W", this.FontLine1).ToSize().Height;
			m_textHeightLine2 = g.MeasureString("W", this.FontLine2).ToSize().Height;
			ItemHeight = m_textHeightLine1 + m_textHeightLine2 + 5;
			g.Dispose();
			RecalcScrollBar();
		}
#endregion

        #region Drawing Methods and Helpers

		protected override void OnDrawItem(object sender, DrawItemEventArgs e)
		{
			string line1Text;
			string line2Text;
			Image image;

			line1Text = GetProperty(e.Index, this.m_line1Property).ToString();
			if (line1Text == null)
				line1Text = Items[e.Index].ToString();

			line2Text = GetProperty(e.Index, this.m_line2Property).ToString();
			if (line2Text == null)
				line2Text = Items[e.Index].ToString();

			if (ImageList != null)
			{
                if (ItemImageDisplayMember != "")
                    image = ImageList.Images[(int)GetProperty(e.Index, this.ItemImageDisplayMember)];
                else
                    if (ImageList.Images.Count > 0)
                        image = ImageList.Images[0];
                    else
                        image = null;
			}
			else
				image = null;
            RenderItem(e, line1Text, line2Text, image);
		}

        protected void RenderItem(DrawItemEventArgs e, string line1Text, string line2Text, Image image)
        {

            // From here on we actually draw things. First the selected background, if necessary
            Rectangle textRect = new Rectangle();	// Destination for the text
            int lineIndent = 0;						// How far the text is moved in from the left margin before drawing

            Brush textBrush;
            if (e.State == DrawItemState.Selected)
            {
                //Highlighted
                e.DrawBackground();
                textBrush = new SolidBrush(SystemColors.HighlightText);
            }
            else
            {
                e.DrawBackground(this.BackColor);
                textBrush = new SolidBrush(this.ForeColor);
            }

            if (image == null)
                lineIndent = TEXT_PADDING_X;
            else
            {
                lineIndent = IMAGE_PADDING_X + image.Width + TEXT_PADDING_X;

                ImageAttributes ia = new ImageAttributes();
                ia.SetColorKey(Color.Cyan, Color.Cyan);
                // Draw the image
                e.Graphics.DrawImage(image,
                    new Rectangle(IMAGE_PADDING_X, e.Bounds.Y + IMAGE_PADDING_Y, ItemHeight - IMAGE_PADDING_Y * 2, ItemHeight - IMAGE_PADDING_Y * 2),
                    0, 0, image.Width, image.Height,
                    GraphicsUnit.Pixel, ia);
            }

            // Calculate the text rectangle
            textRect.X = e.Bounds.X + lineIndent;
            textRect.Width = e.Bounds.Width - TEXT_PADDING_X - textRect.X;	// Allows for padding on the right edge too
            textRect.Y = e.Bounds.Y + 2;
            textRect.Height = this.m_textHeightLine1;

            // Draw the text in a bounding rect to force it to truncate if too long
            e.Graphics.DrawString(line1Text, m_fontLine1, textBrush, textRect);

            // Draw the second line
            textRect.Y += m_textHeightLine1;
            textRect.Height = this.m_textHeightLine2;
            e.Graphics.DrawString(line2Text, m_fontLine2, textBrush, textRect);
            e.Graphics.DrawLine(new Pen(this.ForeColor), e.Bounds.Left, e.Bounds.Bottom - 1, e.Bounds.Right, e.Bounds.Bottom - 1);
        }
        #endregion
	}
}
